#include "touch_key.h"
#include "SysTick.h"
#include "usart.h"

TIM_HandleTypeDef TIM5_Handler;			// 定时器5句柄

#define Touch_ARR_MAX_VAL 0xffff		// 最大的ARR值（TIM5是16位定时器）
u16 touch_default_val;							// 未按下触摸按键时的值


/***************************
* 函数名：TIM5_CH2_Input_Init
* 功能：TIM5_CH2输入捕获初始化函数
* 输入：arr，自动重装载值
*			  psc，预分频系数
* 输出：无
*/
void TIM5_CH2_Input_Init(u32 arr,u16 psc)
{
	TIM_IC_InitTypeDef TIM5_CH2Config;
	
	TIM5_Handler.Instance = TIM5;														// 通用定时器5
	TIM5_Handler.Init.Prescaler = psc;											// 分频
	TIM5_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;			// 向上计数器
	TIM5_Handler.Init.Period = arr;													// 自动装载值
	TIM5_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_IC_Init(&TIM5_Handler);
	
	TIM5_CH2Config.ICPolarity=TIM_ICPOLARITY_RISING;				// 上升沿捕获
	TIM5_CH2Config.ICSelection=TIM_ICSELECTION_INDIRECTTI;	// 映射到TI1上
	TIM5_CH2Config.ICPrescaler=TIM_ICPSC_DIV1;							// 配置输入分频，不分频
	TIM5_CH2Config.ICFilter=0;															// 配置输入滤波器，不滤波
	HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH2Config,TIM_CHANNEL_2); // 配置TIM5通道2
	HAL_TIM_IC_Start(&TIM5_Handler,TIM_CHANNEL_2);					// 开始捕获TIM5的通道2
	
}

/**********************************************
* 定时器底层驱动，时钟使能，引脚配置
* 该函数被HAL_TIM_IC_Init()调用
* htim：定时器句柄
**********************************************/
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	__HAL_RCC_TIM5_CLK_ENABLE();							// 使能TIM5时钟
	__HAL_RCC_GPIOA_CLK_ENABLE();							// 使能GPIOA时钟
		
	GPIO_InitStructure.Pin=GPIO_PIN_1;								// PA1
	GPIO_InitStructure.Mode=GPIO_MODE_AF_INPUT;				// 推挽复用输入
	GPIO_InitStructure.Pull=GPIO_NOPULL;							// 不带上下拉
	GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;		// 高速
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

/************************************************
* 触摸按键复位，先放电然后充电并释放计时器内的值
************************************************/
void Touch_Reset(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.Pin = GPIO_PIN_1;					// PA1
	GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;	// 推挽输出
	GPIO_InitStructure.Pull=GPIO_PULLDOWN;				// 下拉
	GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;// 高速
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET); // PA1输出0，放电
	delay_ms(5);
	__HAL_TIM_CLEAR_FLAG(&TIM5_Handler,TIM_FLAG_CC2|TIM_FLAG_UPDATE); // 清除标志
	__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);							// 计数器值归0
	
	GPIO_InitStructure.Mode=GPIO_MODE_AF_INPUT;					// 推挽复用输入
	GPIO_InitStructure.Pull=GPIO_NOPULL;								// 不带上下拉
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

/**********************************************
* 返回捕获高电平值
**********************************************/
u16 Touch_Get_Val(void)
{
	Touch_Reset();
	while(__HAL_TIM_GET_FLAG(&TIM5_Handler,TIM_FLAG_CC2)==RESET) // 等等捕获上升沿
	{
		if(__HAL_TIM_GET_COUNTER(&TIM5_Handler)>Touch_ARR_MAX_VAL-500)
		{
			return __HAL_TIM_GET_COUNTER(&TIM5_Handler);
		}
	}
	return HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_2);
}

/*********************************************
* 电容触摸按键初始化函数
* psc：分频系数，越小，灵敏度越高
* 输出：0：正常，1：不正常
*********************************************/
u8 Touch_Key_Init(u8 psc)
{
	u8 i;
	u16 buf[10];
	u8 j;
	u16 temp;
	TIM5_CH2_Input_Init(Touch_ARR_MAX_VAL,psc);
	
	for(i=0;i<10;++i) // 读取10次为按下时触摸值
	{
		buf[i]=Touch_Get_Val();
		delay_ms(10);
	}
	for(i=0;i<9;++i) // 从小到大排序
	{
		for(j=i+1;j<10;j++)
		{
			if(buf[i]>buf[j])
			{
				temp=buf[i];
				buf[i]=buf[j];
				buf[j]=temp;
			}
		}
	}
	
	temp = 0;
	for(i=2;i<8;i++) // 取中间6个数值求和 取其平均值
	{
		temp+=buf[i];
	}
	touch_default_val=temp/6;
	printf("touch_default_val=%d \r\n",touch_default_val);
	if(touch_default_val>Touch_ARR_MAX_VAL/2)
	{
		return 1; // 初始化遇到超过Touch_ARR_MAX_VAL/2的值，不正常
	}
	return 0;
}

/********************************************
* 读取n次，取最大值
* 输入：n，连续读取的次数
* 输出：n次读数里读到的最大读数值
********************************************/
u16 Touch_Get_MaxVal(u8 n)
{
	u16 temp=0;
	u16 res=0;
	while(n--)
	{
		temp=Touch_Get_Val(); // 得到一次值
		if(temp>res) res = temp;
	}
	return res;
}


#define TOUCH_GATE_VAL				100		// 触摸的门限值，必须大于touch_default_val+TOUCH_GATE_VAL才认为是有效触摸

/*****************************************************************
* 触摸按键扫描
* 输入：mode，0不支持连续触发（按下一次必须松开一次才能按下一次）
*						  1支持连续触发（可一直按下）
* 输出：0，没有按下
*       1，有按下
*****************************************************************/
u8 Touch_Key_Scan(u8 mode)
{
	static u8 keyen=0;					// 0，可以开始检测，>0，还没开始检测
	u8 res=0;
	u8 sample=3;								// 默认采样次数为3次
	u16 rval;
	if(mode)
	{
		sample=6;									// 支持连续按时，设置采样次数为6次
		keyen=0;									// 支持连按
	}
	rval=Touch_Get_MaxVal(sample);
	if(rval > (touch_default_val+TOUCH_GATE_VAL) && rval < (10*touch_default_val)) // 大于touch_default_val+TOUCH_GATE_VAL，且小于10位touch_default_val才有效
	{
		if((keyen == 0) && (rval > (touch_default_val+TOUCH_GATE_VAL))) // 大于touch_default+TOUCH_GATE_VAL有效
		{
			res=1;
		}
		printf("触摸后捕获高电平值为：%d\r\n",rval);
		keyen=3;									// 至少再过3次后才能按键有效
	}
	if(keyen) keyen--;
	return res;
}